#!/usr/bin/perl  -I lib/
# Ruym'an Reyes Castro
# pssh-copy-id
#
#
#  Script that copies a public key to multiple remote servers
#
#	V 1.5: 
#	 * Some functions moved to the module
#	 * Remote script execution moved to external function
#	 * Included -I lib at the beginning of the script
#	 * More tests
#	 * Some documentation
#
#  V 1.4:
#   * Correct overriding of login method
#   * Check if key exist before adding (Not sure if it works on all kind of environments)
#   * More debug info 
#
#  V 1.3:
#   * Overriding login method so now can connect to machines without password
#   * Smaller remote shell script
#
#  V 1.2 :
#   * Using Net::SSH::Expect
#   * Testing if .ssh/config exists before getting config
#   * Setting a default value to pubkey_file
#   * remote authorized_keys files always exists
#   * Only connect once (Using a remote shell script to check for metakey)
#
#

use strict;
use Carp;

use Term::ReadPassword;
use Getopt::Long;
use Pod::Usage;
use Net::HostLanguage;


use Net::SSH::CopyId qw(
	write_remote_key
	get_users_from_config
	slurp
	$DEBUG
 );

# In case something goes mad, set this to > 0;
# my $DEBUG = 0;

# Important data...
my $pubkey_file;
my $user;
my $nopassword = 0;
my $pass = "\n";


# Get parameters
GetOptions(
	'i=s' => \$pubkey_file, 
	'l=s' => \$user,
	'u=s' => \$user,
   'P'   => \$nopassword,
	'v'   => \$DEBUG,
	'usage' => \&usage,
) or croak usage();

# The last arguments should be the hostnames
#

usage() unless(@ARGV);

my ($cluster, $method) = parse_configfile();

my @hosts = @ARGV;
my $set = Set::Scalar->new();

$set += translate('', $_, $cluster, $method) for @hosts;

@hosts = $set->members();

# Defaults to environment
$user = $ENV{"USER"} unless $user;
# check if a different user is defined in the ~/.ssh/config file
my %config;
%config = get_users_from_config("$ENV{HOME}/.ssh/config") if (-d "$ENV{HOME}/.ssh/config");


# Get the password (using a secure way :)
$pass = read_password('password: ') unless $nopassword;

# Load the file into a variable
#
my $key;

# pubkey_file defaults to id_rsa.pub
$pubkey_file = "$ENV{HOME}/.ssh/id_rsa.pub" unless ($pubkey_file);
# Check for correct extension
$pubkey_file .= '.pub' unless $pubkey_file =~ /\.pub$/;
# File exists and its readable
croak "Error: define an identity file\n" unless ($pubkey_file && -r $pubkey_file);

warn "~~~~~~~~~~ reading id file $pubkey_file\n" if ($DEBUG);
$key = slurp($pubkey_file);
warn "~~~~~~~~~~ reading id file done \n" if ($DEBUG);

# Do the magic...
for (@hosts) {
  my ($user, $host) = ($user, $_);

  # check if a different user was specified for this host
  ($user, $host) = ($1, $2) if /(\w+)\@(.+)/;

  # check if a different user was specified in the config file
  $user =  $config{$host}{user} || $user;

  print "Sending key $pubkey_file to $host as $user \n";

  warn "~~~ Making ssh object ($host, user => $user) ~~~~ \n" if ($DEBUG);
  write_remote_key($key, $host, $user, $pass);
  print "Try logging with 'ssh $host'\n";

}


############## Subroutines

sub usage {
	print <<"END_ERR";
	Incorrect usage, should be:
	pssh-copy-id [-i pubkey_file] [-l|u user] host1 ... hostN
END_ERR
	exit();
}




__END__

=head1 SYNOPSIS

	pssh-copy-id [-i pub_file] [-l|u username] host1 host2 ... hostN 
	pssh-copy-id [-i pub_file] [-l|u username] name1@host1 name2@host2 ... nameN@hostN 

=head1 OPTIONS

Options

=over

=item * C<-i pub_file>   

File where the public key reside, default $HOME/.ssh/id_rsa.pub

=item * C<-l username>

Same as -u, compatibility with ssh options.

=item * C<-u username>

Remote username (must be the same for all the machines)

=item * C<-v> verbose

=back

=head1 AUTHOR

Ruyman Reyes Castro, L<rreyes@ull.es>

Thanks to Casiano Rodriguez-Leon for the idea
